import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.util.Base64;
import java.util.Scanner;

/**
 * 用Java实现RSA加密、解密, 用Java实现SHA512哈希摘要计算
 *
 * @author: wyb
 * @Description: 用Java实现了rsa加解密 和 sha512哈希摘要计算
 * @Encoding: UTF-8
 * @create: 2021/11/26
 *
 * 参考以下内容实现:
 *      Java实现RSA加密解密: http://blog.sina.com.cn/s/blog_6e835b200102wqnj.html
 *      Java实现摘要计算: https://blog.csdn.net/yushuangping/article/details/107659603
 **/
public class javaRSA_SHA512 {

    private static PublicKey publicKey;
    private static PrivateKey privateKey;

    /**
     * 随机生成一对keysize位的公钥和私钥
     * @param keysize 密钥位数: 为了安全性考虑, 至少要1024位, 目前主流可选值：1024、2048、3072、4096...
     * @throws NoSuchAlgorithmException
     */
    public static void generateKey(int keysize) throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(keysize);
        KeyPair keyPair = keyGen.generateKeyPair();
        publicKey = keyPair.getPublic();
        privateKey = keyPair.getPrivate();
    }

    /**
     * SHA256接口: 传入文本内容，返回 SHA-256 串
     *
     * @param strText 原始字符串
     * @return
     */
    public static String SHA256(final String strText) {
        return SHA(strText, "SHA-256");
    }

    /**
     * SHA512接口: 传入文本内容，返回 SHA-512 串
     *
     * @param strText 原始字符串
     * @return
     */
    public static String SHA512(final String strText) {
        return SHA(strText, "SHA-512");
    }

    /**
     * SHAMD5接口: 传入文本内容，返回 md5 串
     *
     * @param strText 原始字符串
     * @return
     */
    public static String SHAMD5(String strText) {
        return SHA(strText, "MD5");
    }

    /**
     * 字符串 SHA 加密
     *
     * @param strText 原始字符串
     * @param strType SHA加密类型, 比如SHA-256\SHA-512\MD5
     * @return
     */
    private static String SHA(final String strText, final String strType) {
        // 返回值
        String strResult = null;

        // 是否是有效字符串
        if (strText != null && strText.length() > 0) {
            try {
                // SHA 加密开始
                // 创建加密对象 并傳入加密類型
                MessageDigest messageDigest = MessageDigest.getInstance(strType);
                // 传入要加密的字符串
                messageDigest.update(strText.getBytes());
                // 得到 byte 類型结果
                byte byteBuffer[] = messageDigest.digest();

                // 將 byte 轉換爲 string
                StringBuffer strHexString = new StringBuffer();
                // 遍歷 byte buffer
                for (int i = 0; i < byteBuffer.length; i++) {
                    String hex = Integer.toHexString(0xff & byteBuffer[i]);
                    if (hex.length() == 1) {
                        strHexString.append('0');
                    }
                    strHexString.append(hex);
                }
                // 得到返回結果
                strResult = strHexString.toString();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }

        return strResult;
    }

    /**
     * RSA加密接口: 用私钥进行RSA加密
     *
     * @param cipher RSA加密机对象
     * @param str 要加密的字符串
     * @return
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] RSAEncode(Cipher cipher, String str) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        byte[] plainText = str.getBytes();
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(plainText);
    }

    /**
     * RSA解密接口: 用公钥进行RSA解密
     *
     * @param cipher RSA加密机对象
     * @param bytes 字节数组
     * @return
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static String RSADecode(Cipher cipher, byte[] bytes) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] plainText = cipher.doFinal(bytes);
        
        return new String(plainText);
    }

    /**
     * 初始化函数: 随机生成公钥和私钥 以及 初始化RSA密码机
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public static Cipher initRSA() throws NoSuchAlgorithmException, NoSuchPaddingException {
        // 随机生成一个2048位的密钥
        generateKey(2048);

        // 初始化RSA密码机
        return Cipher.getInstance("RSA");
    }


    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {

        System.out.print("请输入明文:");
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        System.out.println("输入的字符串为: " + str);

        // 初始化密钥和RSA密码机
        Cipher cipher = initRSA();

        // RSA加密调用方法
        byte[] cipherbytes = RSAEncode(cipher, str);
        // 注意: 这里必须要用Base64进行编码 否则会乱码
        System.out.println("RSA加密后的密文: " + Base64.getEncoder().encodeToString(cipherbytes));

        // RSA解密调用方法
        String plaintext = RSADecode(cipher, cipherbytes);
        System.out.println("RSA解密后的明文: " + plaintext);

        // SHA512计算
        String digest = SHA512(str);
        System.out.println("SHA512摘要: " + digest);

    }

}
